////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxchisession.cpp
/// @brief Definitions for CHISession class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxatomic.h"
#include "camxchisession.h"
#include "camxhaldevice.h"
#include "camxhwcontext.h"
#include "camxmemspy.h"

CAMX_NAMESPACE_BEGIN

extern CHICALLBACKS  g_callbacks;

/// @todo (CAMX-1797) Not sure if we need anything fancy, quickly rethink
volatile UINT CHISession::s_numInstances = 0;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::~CHISession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CHISession::~CHISession()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::UnregisterThreadJobCallback
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CHISession::UnregisterThreadJobCallback()
{
    if (InvalidJobHandle != m_hJobFamilyHandle)
    {
        CHAR wrapperName[FILENAME_MAX];
        OsUtils::SNPrintF(&wrapperName[0], sizeof(wrapperName), "CHISessionWrapper%d", m_localInstance);
        m_pThreadManager->UnregisterJobFamily(ThreadJobCallback, wrapperName, m_hJobFamilyHandle);
        m_hJobFamilyHandle = InvalidJobHandle;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::Destroy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CHISession::Destroy(
    BOOL isForced)
{
    Session::Destroy(isForced);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::Create
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CHISession* CHISession::Create(
    CHISessionCreateData* pCreateData)
{
    CamxResult  result      = CamxResultSuccess;
    // 创建返回对象
    CHISession* pCHISession = CAMX_NEW CHISession;

    if (NULL != pCHISession)
    {
        result = pCHISession->Initialize(pCreateData);

        if (CamxResultSuccess != result)
        {
            pCHISession->Destroy(FALSE);
            pCHISession = NULL;
        }
    }
    else
    {
        CAMX_ASSERT_ALWAYS_MESSAGE("CHISession: Couldn't create CHISession object - out of memory");
        result = CamxResultENoMemory;
    }

    return pCHISession;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::Initialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CHISession::Initialize(
    CHISessionCreateData* pCreateData)
{
    CamxResult result = CamxResultSuccess;
    CHAR wrapperName[FILENAME_MAX];

    CAMX_ASSERT(NULL != pCreateData);
    CAMX_ASSERT(NULL != pCreateData->sessionCreateData.pThreadManager);
    CAMX_ASSERT(NULL != pCreateData->sessionCreateData.pChiContext);

    result = Session::Initialize(&pCreateData->sessionCreateData);

    if (CamxResultSuccess == result)
    {
        m_localInstance = CamxAtomicIncU(&s_numInstances);
        OsUtils::SNPrintF(&wrapperName[0], sizeof(wrapperName), "CHISessionWrapper%d", m_localInstance);

        result = m_pThreadManager->RegisterJobFamily(ThreadJobCallback,
                                                     wrapperName,
                                                     NULL,
                                                     JobPriority::Normal,
                                                     TRUE,
                                                     &m_hJobFamilyHandle);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::ThreadJobCallback
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* CHISession::ThreadJobCallback(
    VOID* pData)
{
    CamxResult  result   = CamxResultEFailed;
    CHISession* pSession = reinterpret_cast<CHISession*>(pData);

    if (NULL != pSession)
    {
        result = pSession->ThreadJobExecute();

        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupHAL, "Chi workerCore failed with result %s", CamxResultStrings[result]);
        }
    }

    return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::ThreadJobExecute
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CHISession::ThreadJobExecute()
{
    CamxResult result = CamxResultSuccess;

    // First process the Results
    if (TRUE == static_cast<BOOL>(CamxAtomicLoad32(&m_aCheckResults)))
    {
        CamxAtomicStore32(&m_aCheckResults, FALSE);
        // 处理结果
        result = ProcessResults();
    }

    if (CamxResultSuccess == result)
    {
        // If nothing catastrophic occurred, process the Requests
        result = ProcessRequest();
    }
    else
    {
        // Otherwise flush everything, as it is a device error
        FlushRequests(FALSE);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::InitializeOutResults
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CHISession::InitializeOutResults(
    const Camera3CaptureResult* pCaptureResults,
    Camera3CaptureResult*       pOutResults)
{
    pOutResults->frameworkFrameNum  = pCaptureResults->frameworkFrameNum;
    pOutResults->pResultMetadata    = pCaptureResults->pResultMetadata;
    pOutResults->numOutputBuffers   = 0;
    pOutResults->pInputBuffer       = pCaptureResults->pInputBuffer;
    pOutResults->numPartialMetadata = pCaptureResults->numPartialMetadata;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::DispatchResults
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CHISession::DispatchResults(
    ChiCaptureResult* pCaptureResults,
    UINT32            numCaptureResults)
{
    CamxResult result = CamxResultSuccess;

    for (UINT32 i = 0; i < numCaptureResults; i++)
    {
        CAMX_LOG_INFO(CamxLogGroupHAL,
                      "Sending Chi override client result for frame: %d, numOutputBuffers: %d, Metadata:%p,"
                      "numPartial:%d, priv = %p",
                      pCaptureResults[i].frameworkFrameNum,
                      pCaptureResults[i].numOutputBuffers,
                      pCaptureResults[i].pResultMetadata,
                      pCaptureResults[i].numPartialMetadata,
                      pCaptureResults[i].pPrivData);

        m_chiCallBacks.ChiProcessCaptureResult(&pCaptureResults[i], m_pPrivateCbData);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHISession::DispatchNotify
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CHISession::DispatchNotify(
    ChiMessageDescriptor* pNotifyMessage)
{
    CAMX_UNREFERENCED_PARAM(pNotifyMessage);

    CamxResult result = CamxResultSuccess;

    m_chiCallBacks.ChiNotify(pNotifyMessage, m_pPrivateCbData);

    return result;
}

CAMX_NAMESPACE_END
